#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "flightMS.h"

// 创建双向循环链表的头
dclist_t *create_dclist()
{

    dclist_t *dchead = (dclist_t *)malloc(sizeof(dclist_t));
    if (dchead == NULL)
    {
        perror("malloc failed\n");
        return NULL;
    }
    // 初始化
    dchead->flight = NULL;
    dchead->before = dchead;
    dchead->next = dchead;

    return dchead;
}

// 添加航班(尾插)
int insert_flight(dclist_t *dchead, flight_t *flight)
{

    if (dchead == NULL || flight == NULL)
    {
        perror("error\n");
        return -1;
    }

    // 申请节点空间
    dclist_t *newnode = (dclist_t *)malloc(sizeof(dclist_t));
    if (newnode == NULL)
    {
        perror("malloc failed\n");
        return -1;
    }

    // 申请数据空间
    newnode->flight = (flight_t *)malloc(sizeof(flight_t));
    if (newnode->flight == NULL)
    {
        perror("malloc failed\n");
        return -1;
    }

    // 赋值
    //*newnode->flight = *flight;
    // memcpy 用于复制一块内存区域的内容到另一块内存区域。
    //    原型：void *memcpy(void *dest, const void *src, size_t n);
    // 参数：
    // @dest：目标内存区域的指针。
    // @src：源内存区域的指针。
    // @n：要复制的字节数。
    // 行为：memcpy 从 src 指向的内存区域复制 n 个字节到 dest 指向的内存区域。它不关心内存区域的内容是什么类型，只是简单地按字节复制。
    // 注意事项：memcpy 不检查目标内存区域是否有足够的空间来容纳复制的字节数，因此使用时需要确保目标区域有足够的空间。
    memcpy(newnode->flight, flight, sizeof(flight_t));
    newnode->before = dchead->before; // 双向循环链表 newnode->before 指向最后一个节点、
    newnode->next = dchead;

    dchead->before->next = newnode;
    dchead->before = newnode;

    return 0;
}

// 节点数，不包括头
int length_dclist(dclist_t *dchead)
{
    if (dchead == NULL || dchead->next == dchead)
    {
        perror("error\n");
        return -1;
    }

    dclist_t *temp = dchead->next;
    int i = 1;
    while (temp->next != dchead)
    {
        ++i;
        temp = temp->next;
    }

    return i;
}

// 打印定义的函数指针
// 定义了一个名为 showfun_t 的函数指针类型，
// 该类型指向一个接受 flight_t 类型指针作为参数并且没有返回值的函数。
typedef void (*showfun_t)(flight_t *flight);
void showId(flight_t *flight)
{
    printf("航班号%s\n", flight->id);
}
void showRoute(flight_t *flight)
{
    printf("航线：%s-----%s\n", flight->begaddr, flight->endaddr);
}
void showTime(flight_t *flight)
{
    printf("时间段：%s-----%s\n", flight->begtime, flight->endtime);
}
void showFare(flight_t *flight)
{
    printf("票价：%.2f\n", flight->fare);
}
void showData(flight_t *flight)
{
    printf("航班日期：%s\n", flight->fldate);
}
void showType(flight_t *flight)
{
    printf("航班类型：%s\n", flight->fltype);
}
void showAll(flight_t *flight)
{
    printf("%s  %s---->%s   %s  %s     %s      %s     %.2f\n",
           flight->id, flight->begaddr, flight->endaddr,
           flight->fldate, flight->fltype, flight->begtime,
           flight->endtime, flight->fare);
    puts("");
}

// 打印函数
void print_flight(dclist_t *dchead, showfun_t showFun)
{

    if (dchead == NULL || dchead->next == dchead)
    {
        perror("error\n");
        return;
    }

    dclist_t *temp = dchead->next;
    printf("航班号  起始站  终点站  航班日期    航班类型    起飞时间   降落时间    票价\n");
    while (temp != dchead)
    {
        showFun(temp->flight);
        temp = temp->next;
    }
}

// 比较函数指针(第一个是链表中本身的数据，第二个是页面传过来的数据)   回调函数，函数指针
typedef int (*comparefun_t)(flight_t *dclistFlight, flight_t *flight);
int compareId(flight_t *dclistFlight, flight_t *flight)
{
    return strcmp(dclistFlight->id, flight->id);
}
int compareType(flight_t *dclistFlight, flight_t *flight)
{
    return strcmp(dclistFlight->fltype, flight->fltype);
}

int compareFldate(flight_t *dclistFlight, flight_t *flight)
{
    return strcmp(dclistFlight->fldate, flight->fldate);
}

// 比较起始地和目的地
int compareAddress(flight_t *dclistFlight, flight_t *flight)
{
    int beg = strcmp(dclistFlight->begaddr, flight->begaddr);
    int end = strcmp(dclistFlight->endaddr, flight->endaddr);

    if (beg == 0 && end == 0)
    {
        return 0;
    }

    return -1;
}

// 根据航班号删除航班
int delete_dclist(dclist_t *dchead, flight_t *flight, comparefun_t comparefun)
{

    if (dchead == NULL || dchead->next == dchead || flight == NULL)
    {
        perror("error\n");
        return -1;
    }

    dclist_t *temp = dchead->next;
    int res;
    while (temp != dchead)
    {
        res = comparefun(temp->flight, flight);
        if (res == 0)
        {
            temp->before->next = temp->next;
            temp->next->before = temp->before;
            free(temp->flight);
            free(temp);
            return 0;
        }
        temp = temp->next;
    }

    return -1;
}

// 删除链表中的尾节点，读文件最后一行重复读
int delete_tdclist(dclist_t *dchead)
{

    if (dchead == NULL)
    {
        perror("error\n");
        return -1;
    }

    dclist_t *temp = dchead->before;
    temp->before->next = temp->next;
    temp->next->before = temp->before;

    free(temp->flight);
    free(temp);

    return 0;
}

// 根据航班号修改航班中时间信息
int updata_dclist(dclist_t *dchead, flight_t *flight, comparefun_t comparefun)
{

    if (dchead == NULL || dchead->next == dchead || flight == NULL)
    {
        perror("error\n");
        return -1;
    }

    // 先查找出对应的航班
    dclist_t *temp = dchead->next;
    while (temp != dchead)
    {
        if (!comparefun(temp->flight, flight))
        {
            break;
        }
        temp = temp->next;
    }

    if (temp == dchead)
    {
        perror("无此航班号\n");
        return -1;
    }

    // 修改原航班的起飞时间，和降落时间
    strcpy(temp->flight->begtime, flight->begtime);
    strcpy(temp->flight->endtime, flight->endtime);

    return 0;
}

// 按照类型查询航班
int find_flight_type(dclist_t *dchead, flight_t *flight, comparefun_t comparefun, showfun_t showfun)
{

    if (dchead == NULL || dchead->next == dchead || flight == NULL)
    {
        perror("error\n");
        return -1;
    }

    dclist_t *temp = dchead->next;
    while (temp != dchead)
    {
        if (!comparefun(temp->flight, flight))
        {
            showfun(temp->flight);
        }
        temp = temp->next;
    }

    return 0;
}

// 根日期票价排序查看航班
int sort_flight_date_fare(dclist_t *dchead)
{

    if (dchead == NULL || dchead->next == dchead)
    {
        perror("error\n");
        return -1;
    }
    int len = length_dclist(dchead);
    flight_t *arr[len];
    dclist_t *temp = dchead->next;
    int i = 0;
    // 讲链表中的数据全部放入指针数组中
    while (temp != dchead)
    {
        arr[i] = temp->flight;
        temp = temp->next;
        ++i;
    }

    // 将数组中的航班进行排序
    flight_t *temp2 = NULL;
    for (int j = 0; j < len - 1; j++)
    {
        for (int k = 0; k < len - 1 - j; k++)
        {
            if (compareFldate(arr[k], arr[k + 1]) > 0)
            {
                temp2 = arr[k];
                arr[k] = arr[k + 1];
                arr[k + 1] = temp2;
            }
            if (!compareFldate(arr[k], arr[k + 1]))
            {
                if (arr[k]->fare > arr[k + 1]->fare)
                {
                    temp2 = arr[k];
                    arr[k] = arr[k + 1];
                    arr[k + 1] = temp2;
                }
            }
        }
    }

    temp = NULL;

    // 遍历输出数组中的元素
    for (int z = 0; z < len; z++)
    {
        /*printf("航班号:%s\t起始站:%s\t终点站:%s\t航班日期:%s\t航班类型:%s\t起飞时间:%s\t降落时间:%s\t票价:%.2f\n",
           arr[z]->id, arr[z]->begaddr, arr[z]->endaddr,
           arr[z]->fldate, arr[z]->fltype, arr[z]->begtime,
           arr[z]->endtime, arr[z]->fare);
        puts("");*/

        showAll(arr[z]);
    }
    return 0;
}

// 根据起始地和目的地查询航班
int find_flight_begaddr_endaddr(dclist_t *dchead, flight_t *flight)
{

    if (dchead == NULL || flight == NULL || dchead->next == dchead)
    {
        return -1;
    }

    dclist_t *temp = dchead->next;
    while (temp != dchead)
    {
        if (!compareAddress(temp->flight, flight))
        {
            showAll(temp->flight);
        }
        temp = temp->next;
    }

    return 0;
}

// 根据日期查询航班
int find_flight_fldate(dclist_t *dchead, flight_t *flight)
{
    if (dchead == NULL || flight == NULL || dchead->next == dchead)
    {
        return -1;
    }

    dclist_t *temp = dchead->next;
    while (temp != dchead)
    {
        if (!compareFldate(temp->flight, flight))
        {
            showAll(temp->flight);
        }
        temp = temp->next;
    }

    return 0;
}

#if 1
// 从链表中的数据保存到文件中
void save_flight_file(dclist_t *dchead)
{

    if (dchead == NULL)
    {
        perror("error\n");
        return;
    }

    FILE *fp;
    fp = fopen("flightFile.txt", "w+");
    fprintf(fp, "航班号  起始站  终点站  航班日期    航班类型    起飞时间    降落时间    票价\n");
    dclist_t *temp = dchead->next;
    while (temp != dchead)
    {
        fprintf(fp, "%s\t%s\t%s\t%s\t%s\t%s\t%s\t%.2f\n", temp->flight->id, temp->flight->begaddr, temp->flight->endaddr,
                temp->flight->fldate, temp->flight->fltype, temp->flight->begtime,
                temp->flight->endtime, temp->flight->fare);
        temp = temp->next;
    }

    fclose(fp);
}

#endif

// 添加一条航班就往文件中保存
void write_flight_file(dclist_t *dchead)
{

    if (dchead == NULL)
    {
        perror("error\n");
        return;
    }
    // 文件指针
    FILE *fp;
    fp = fopen("flightFile.txt", "a");
    if (fp == NULL)
    {
        perror("打开文件失败\n");
        return;
    }

    dclist_t *temp = dchead->before;
    fprintf(fp, "%s %s %s %s %s %s %s %.2f\n", temp->flight->id, temp->flight->begaddr, temp->flight->endaddr, temp->flight->fldate, temp->flight->fltype, temp->flight->begtime, temp->flight->endtime, temp->flight->fare);
    fclose(fp);
}

// 从文件中读取航班
void read_flight_file(dclist_t *dchead)
{

    if (dchead == NULL)
    {
        perror("error\n");
        return;
    }
    // 文件指针
    FILE *fp;
    char buf[1024];
    char id[16], begaddr[16], endaddr[16], fldate[16], fltype[16], begtime[8], endtime[8];

    fp = fopen("flightFile.txt", "r");
    if (fp == NULL)
    {
        perror("打开文件失败\n");
        return;
    }

    // 不读第一行
    fgets(buf, sizeof(buf), fp);
    flight_t flight;
    while (!feof(fp)) // feof(fp)表示是否到达文件末尾，到达返回非零值，否则返回0
    {

        fscanf(fp, "%s %s %s %s %s %s %s %f", id, begaddr, endaddr, fldate, fltype, begtime, endtime, &flight.fare);
        strcpy(flight.id, id);
        strcpy(flight.begaddr, begaddr);
        strcpy(flight.endaddr, endaddr);
        strcpy(flight.fldate, fldate);
        strcpy(flight.fltype, fltype);
        strcpy(flight.begtime, begtime);
        strcpy(flight.endtime, endtime);
        insert_flight(dchead, &flight);
    }

    fclose(fp);
}